package com.tc.itfarm.commons.interceptor;

import com.tc.itfarm.api.util.DateUtils;
import com.tc.itfarm.api.util.JsonMapper;
import com.tc.itfarm.dao.LogDao;
import com.tc.itfarm.model.Log;
import com.tc.itfarm.model.User;
import com.tc.itfarm.service.LogService;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.shiro.SecurityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.ContextLoader;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.support.WebApplicationContextUtils;

import java.lang.reflect.InvocationTargetException;
import java.util.Properties;

/**
 * mybatic拦截器 用于打印日志
 * Created by wangdongdong on 2016/8/17.
 */
@Intercepts({@Signature(method = "update", type = Executor.class, args = {MappedStatement.class, Object.class})})
public class LogInterceptor implements Interceptor {
    /**
     * 注解拦截接口的方法
     * Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
     * ParameterHandler (getParameterObject, setParameters)
     * ResultSetHandler (handleResultSets, handleOutputParameters)
     * StatementHandler (prepare, parameterize, batch, update, query)
     */

    private static final Logger LOGGER = LoggerFactory.getLogger(LogInterceptor.class);

    public Object intercept(Invocation invocation) throws Throwable {
        Object[] args = invocation.getArgs();
        // 获取执行的方法
        if (args.length > 1) {
            // 传入的对象
            Object obj = args[1];
            if (obj instanceof Log) {
                // 若是日志对象 则直接跳过
                return invocation.proceed();
            }
            return saveLog(args[0], obj, invocation);
        }
        return invocation.proceed();
    }

    /**
     * 保存日志
     * @param arg
     * @param obj
     */
    private Object saveLog(Object arg, Object obj, Invocation invocation) throws InvocationTargetException, IllegalAccessException {
        Log log = new Log();
        log.setCreateTime(DateUtils.now());
        log.setModifyTime(DateUtils.now());
        MappedStatement mappedStatement = (MappedStatement) arg;
        // 执行的方法类型
        String name = mappedStatement.getSqlCommandType().name();
        // 执行的方法
        String method = mappedStatement.getId();
        if (method.endsWith("addPageView")) {
            return invocation.proceed();
        }
        // 操作的Model类型
        String modelName = this.getModelName(method);
        // 改变的内容
        String change = JsonMapper.toJson(obj);
        // 组装日志对象
        this.constructLog(log, name, method, modelName, change);
        LOGGER.info("----------------------------------------------");
        LOGGER.info(JsonMapper.toJson(log));
        LOGGER.info("----------------------------------------------");
        return invocation.proceed();
    }

    /**
     * 组装日志
     * @param log
     * @param name
     * @param method
     * @param modelName
     * @param change
     */
    private void constructLog(Log log, String name, String method, String modelName, String change) {
        if (name.startsWith("INSERT")) {
            log.setType("新增" + modelName);
            log.setNewContent(change);
            log.setOldContent("执行方法" + method);
        } else if (name.startsWith("UPDATE")) {
            log.setType("修改" + modelName);
            log.setNewContent(change);
            log.setOldContent("执行方法" + method);
        } else if (name.startsWith("DELETE")) {
            log.setType("删除" + modelName);
            log.setOldContent("删除id为" + change);
            log.setNewContent("执行方法" + method);
        }
        WebApplicationContext webApplicationContext = ContextLoader.getCurrentWebApplicationContext();
        LogService logService = webApplicationContext.getBean(LogService.class);
        User user = (User) SecurityUtils.getSubject().getPrincipal();
        log.setUserId(user.getRecordId());
        log.setUsername(user.getUsername());
        logService.insert(log);
    }

    /**
     * 获取操作Model
     * @param method
     * @return
     */
    private String getModelName(String method) {
        if (method.contains("Dao")) {
            String typeName = method.substring(0, method.lastIndexOf("Dao"));
            typeName = typeName.substring(18);
            return typeName;
        }
        return StringUtils.EMPTY;
    }

    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {

    }

}
